CONSTANT_Utf8 = 1
CONSTANT_Integer = 3
CONSTANT_Float = 4
CONSTANT_Long = 5
CONSTANT_Double = 6
CONSTANT_Class = 7
CONSTANT_String = 8
CONSTANT_Fieldref = 9
CONSTANT_Methodref = 10
CONSTANT_InterfaceMethodref = 11
CONSTANT_NameAndType = 12

CONSTANT_MethodHandle = 15
CONSTANT_MethodType = 16
CONSTANT_InvokeDynamic = 18


# 根据具体的 tag 值 构造 具体的常量
def create_constant_info(classReader):
    # 读取tag值 一个字节
    tag = classReader.read_u1()
    if tag == CONSTANT_Integer:
        return ConstantIntegerInfo()
    if tag == CONSTANT_Float:
        return ConstantFloatInfo()
    if tag == CONSTANT_Long:
        return ConstantLongInfo()
    if tag == CONSTANT_Double:
        return ConstantDoubleInfo()
    if tag == CONSTANT_Utf8:
        return ConstantUtf8Info()
    if tag == CONSTANT_String:
        return ConstantStringInfo()
    if tag == CONSTANT_Class:
        return ConstantClassInfo()
    if tag == CONSTANT_Fieldref:
        return ConstantFieldRefInfo()
    if tag == CONSTANT_Methodref:
        return ConstantMethodRefInfo()
    if tag == CONSTANT_InterfaceMethodref:
        return ConstantInterfaceMethodRefInfo()
    if tag == CONSTANT_NameAndType:
        return ConstantNameAndTypeInfo()
    if tag == CONSTANT_MethodType:
        return ConstantMethodTypeInfo()
    if tag == CONSTANT_MethodHandle:
        return ConstantMethodHandleInfo()
    if tag == CONSTANT_InvokeDynamic:
        return ConstantInvokeDynamicInfo()


class ConstantInfo:

    def get_val(self):
        pass


#  字符串常量 ：CONSTANT_Utf8_info
class ConstantUtf8Info(ConstantInfo):

    def __init__(self):
        # 具体的 string 值
        self.val = None

    def read(self, classReader):
        # 读取字符串 字符长度
        len_str = classReader.read_u2()
        # 读取指定长度的字节，也就是 字符串内容
        data = classReader.read_bytes(len_str)
        # 将字节转换成 字符串
        self.val = str(data, encoding='utf-8')

    def get_val(self):
        return self.val


# CONSTANT_Integer_info使用4字节存储整数常量
# CONSTANT_Integer_info正好可以容纳一个Java的int型常量，但实际上比int更小的
# boolean、byte、short和char类型的常量也放在CONSTANT_Integer_info中
class ConstantIntegerInfo(ConstantInfo):

    def __init__(self):
        # 具体的int值
        self.val = None

    def read(self, classReader):
        #  一个 int 占4个字节， 所以读取 4个字节 得到值
        self.val = classReader.read_u4()


#  Float 常量 ：CONSTANT_Float_info使用4字节存储IEEE754单精度浮点数常量
class ConstantFloatInfo(ConstantInfo):

    def __init__(self):
        # 具体的 flaot 值
        self.val = None

    def read(self, classReader):
        # 读取 4个字节数据 ，然后转成float
        self.val = float(classReader.read_u4())


#   Long常量 ：CONSTANT_Long_info使用8字节存储整数常量
class ConstantLongInfo(ConstantInfo):

    def __init__(self):
        # 具体的 long 值
        self.val = None

    def read(self, classReader):
        # 读取 8个字节数据 ，然后转成 long
        self.val = classReader.read_u8()


#  double常量 ：CONSTANT_Double_info，使用8字节存储IEEE754双精度浮点数
class ConstantDoubleInfo(ConstantInfo):

    def __init__(self):
        # 具体的 double 值
        self.val = None

    def read(self, classReader):
        # 读取 8个字节数据 ，然后转成double
        self.val = float(classReader.read_u8())


# java.lang.String字面量常量 ：CONSTANT_String_info
# CONSTANT_String_info本身并不存放字符串数据，只存了常量池索引，这个索引指向一个CONSTANT_Utf8_info常量
class ConstantStringInfo(ConstantInfo):

    def __init__(self):
        # 在 常量池中的索引
        self.index = None

    def read(self, classReader):
        # 读取字符串 索引
        self.index = classReader.read_u2()

    def get_index(self):
        return self.index


# 类或者接口的符号引用 ：CONSTANT_Class_info
class ConstantClassInfo(ConstantInfo):

    def __init__(self):
        # 在utf8常量池中的索引
        self.index = None

    def read(self, classReader):
        # 读取索引
        self.index = classReader.read_u2()

    def get_index(self):
        return self.index

    def get_val(self):
        return self.get_index()


# 字段符号引用 ：CONSTANT_Fieldref_info
# 组成部分： CONSTANT_Class_info和CONSTANT_NameAndType_info常量
class ConstantFieldRefInfo(ConstantInfo):

    def __init__(self):
        # 在 常量池中的索引
        self.classIndex = None
        self.nameAndTypeIndex = None

    def read(self, classReader):
        # 读取索引
        self.classIndex = classReader.read_u2()
        self.nameAndTypeIndex = classReader.read_u2()

    def get_class_index(self):
        return self.classIndex

    def get_name_and_type_index(self):
        return self.nameAndTypeIndex


# 普通（非接口）方法符号引用：CONSTANT_Methodref_info
# 组成部分： CONSTANT_Class_info和CONSTANT_NameAndType_info常量
class ConstantMethodRefInfo(ConstantInfo):

    def __init__(self):
        # 在 常量池中的索引
        self.classIndex = None
        self.nameAndTypeIndex = None

    def read(self, classReader):
        # 读取索引
        self.classIndex = classReader.read_u2()
        self.nameAndTypeIndex = classReader.read_u2()

    def get_class_index(self):
        return self.classIndex

    def get_name_and_type_index(self):
        return self.nameAndTypeIndex


# 接口方法符号引用：CONSTANT_InterfaceMethodref_info
# 组成部分： CONSTANT_Class_info和CONSTANT_NameAndType_info常量
class ConstantInterfaceMethodRefInfo(ConstantInfo):

    def __init__(self):
        # 在 常量池中的索引
        self.classIndex = None
        self.nameAndTypeIndex = None

    def read(self, classReader):
        # 读取索引
        self.classIndex = classReader.read_u2()
        self.nameAndTypeIndex = classReader.read_u2()

    def get_class_index(self):
        return self.classIndex

    def get_name_and_type_index(self):
        return self.nameAndTypeIndex


# 字段或方法的名称和描述符 ：CONSTANT_NameAndType_info
# 由于java有重载，所以仅凭 方法名是无法确定调用哪个方法的，于是要 名称和描述符 来确定
# 方法描述符如： (Ljava.lang.String;)V;   表示 void xxx(String[] args)
# 字段的描述符如：  [L]java.lang.String;  表示 java.lang.String[]
class ConstantNameAndTypeInfo(ConstantInfo):

    def __init__(self):
        # 方法名称 在常量池中的索引
        self.nameIndex = None
        # 描述符 在常量池的索引
        self.descIndex = None

    def read(self, classReader):
        # 读取索引
        self.nameIndex = classReader.read_u2()
        self.descIndex = classReader.read_u2()

    def get_name_index(self):
        return self.nameIndex

    def get_desc_index(self):
        return self.descIndex


# 方法类型：CONSTANT_MethodType_info
class ConstantMethodTypeInfo(ConstantInfo):

    def __init__(self):
        # 值必须在1 到 9之间,决定了 方法句柄的类型
        self.descIndex = None

    def read(self, classReader):
        # 读取索引
        self.descIndex = classReader.read_u2()

    def get_desc_index(self):
        return self.classIndex


# CONSTANT_MethodType_info、CONSTANT_MethodHandle_info和CONSTANT_InvokeDynamic_info。
# 它们是Java SE 7才添加到class文件中的，目的是支持新增的invokedynamic指令。
class ConstantMethodHandleInfo(ConstantInfo):

    def __init__(self):
        # 值必须在1 到 9之间,决定了 方法句柄的类型
        self.referenceKind = None
        self.referenceIndex = None

    def read(self, classReader):
        # 读取索引
        self.referenceKind = classReader.read_u1()
        self.referenceIndex = classReader.read_u2()

    def get_reference_kind(self):
        return self.referenceKind

    def get_reference_index(self):
        return self.referenceIndex


# 接口方法符号引用：CONSTANT_InvokeDynamic_info
# 在java7 JVM中增加了一个新的指令invokedynamic，用于支持动态语言，即允许方法调用可以在运行时指定类和方法，
# 不必在编译的时候确定。字节码中每条invokedynamic指令出现的位置称为一个动态调用点，
# invokedynamic指令后面会跟一个指向常量池的调用点限定符，这个限定符会被解析为一个动态调用点。
class ConstantInvokeDynamicInfo(ConstantInfo):

    def __init__(self):
        # 在 常量池中的索引
        self.bootstrapMethodAttrIndex = None
        self.nameAndTypeIndex = None

    def read(self, classReader):
        # 读取索引
        self.bootstrapMethodAttrIndex = classReader.read_u2()
        self.nameAndTypeIndex = classReader.read_u2()

    def get_bootstrap_method_attr_index(self):
        return self.classIndex

    def get_name_and_type_index(self):
        return self.nameAndTypeIndex
